using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Diagnostics;


namespace CGShaderIntegration.DrawableGameComponents
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class SasenoWidyaSunSys : Microsoft.Xna.Framework.DrawableGameComponent, IMatrices
    {
        ContentManager 
            Content;

        SpriteBatch 
            spriteBatch;

        Model 
            sun_, 
            earth_,  
            moon_;
                
        Vector3 
            earthPos = new Vector3(0, 10f, 0), 
            sunPos = Vector3.Zero, 
            moonPos = new Vector3(0, 5f, 0), 
            cameraPos = new Vector3(0.0f, 50.0f, 300.0f);

        float 
            aspectRatio, 
            moonRotation = 0.0f;

        double 
            earth_rotation, 
            moon_rotation;

        Matrix 
            _sunWrldMtrx, 
            _earthWrldMtrx, 
            _moonWrldMtrx;

        Effect effect_;
        
        public Matrix 
            WorldMatrix { get; set; }

        public Matrix 
            ViewMatrix { get; set; }

        public Matrix 
            ProjectionMatrix { get; set; }

        public SasenoWidyaSunSys (Game game)
            : base(game)
        {
            this.Content = game.Content;
            this.aspectRatio = game.GraphicsDevice.Viewport.AspectRatio;
            game.Components.Add(this);
            
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization logic here
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            sun_   = Content.Load<Model>("models\\earth");
            earth_ = Content.Load<Model>("models\\earth");
            moon_  = Content.Load<Model>("models\\earth");

            effect_ = Content.Load<Effect>("effects\\SasenoWidyaSchachbrett");
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Game.Exit();

            //update rotation...
            {
                moon_rotation -= 0.05f;    //cw
                earth_rotation += 0.01f;    //ccw
            }            
            
            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Draw(GameTime gameTime)
        {
            //sun...
            {
                Matrix[] __Sun = new Matrix[sun_.Bones.Count];
                sun_.CopyAbsoluteBoneTransformsTo(__Sun);
                foreach (ModelMesh mesh in sun_.Meshes)
                {

                    foreach (ModelMeshPart part in mesh.MeshParts)
                    {
                        _sunWrldMtrx = 1
                            * (Matrix.CreateScale(3f)
                            * Matrix.CreateTranslation(new Vector3(0, 0, 0)))
                            * WorldMatrix
                            ;

                        part.Effect = effect_;
                        part.Effect.Parameters["World"].SetValue(_sunWrldMtrx);
                        part.Effect.Parameters["View"].SetValue(ViewMatrix);
                        part.Effect.Parameters["Projection"].SetValue(ProjectionMatrix);
                    }

                    mesh.Draw();
                }
            }

            //earth...
            {
                Matrix[] __Earth = new Matrix[earth_.Bones.Count];
                earth_.CopyAbsoluteBoneTransformsTo(__Earth);
                foreach (ModelMesh mesh in earth_.Meshes)
                {
                    foreach (ModelMeshPart part in mesh.MeshParts)
                    {
                        _earthWrldMtrx = 1
                            * Matrix.CreateScale(0.5f)
                            * Matrix.CreateTranslation(new Vector3(0, 4f, 0.0f))
                            * Matrix.CreateRotationZ((float)earth_rotation)
                            * _sunWrldMtrx
                            ;

                        part.Effect = effect_;
                        part.Effect.Parameters["World"].SetValue(_earthWrldMtrx);
                        part.Effect.Parameters["View"].SetValue(ViewMatrix);
                        part.Effect.Parameters["Projection"].SetValue(ProjectionMatrix);
                    }
                    mesh.Draw();
                }
            }


            //moon...
            {
                Matrix[] __Moon = new Matrix[moon_.Bones.Count];
                moon_.CopyAbsoluteBoneTransformsTo(__Moon);
                foreach (ModelMesh mesh in moon_.Meshes)
                {
                    foreach (ModelMeshPart part in mesh.MeshParts)
                    {
                        _moonWrldMtrx = 1
                            * Matrix.CreateScale(0.6f)
                            * Matrix.CreateTranslation(new Vector3(0, 4f, 0.0f))
                            * Matrix.CreateRotationZ((float)moon_rotation * 0.9f)
                            * _earthWrldMtrx
                            ;
                        
                        part.Effect = effect_;
                        part.Effect.Parameters["World"].SetValue(_moonWrldMtrx);
                        part.Effect.Parameters["View"].SetValue(ViewMatrix);
                        part.Effect.Parameters["Projection"].SetValue(ProjectionMatrix);
                    }

                    mesh.Draw();
                }
            }


            base.Draw(gameTime);
        }

        public String GetName()
        {
            return "SasenoWidya";
        }
    }
}
